﻿using System;
using System.Linq;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
using NLog;
using ZOIL.DataModel;
using ZOIL.Framework.Core;
using ZOIL.Framework.Presentation;

namespace ZOIL.Library.Behaviors
{
    public class PluginConnectionBehavior : PluginBehavior<ZLandscapeCanvas, ConnectionBehavior>
    {
        #region Logger

        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

        #endregion

        #region private fields

        private AdornerLayer _adornerLayer;

        #endregion

        #region protected properties

        protected AdornerLayer AdornerLayer
        {
            get
            {
                if (_adornerLayer == null)
                {
                    var window = Window.GetWindow(AssociatedObject);

                    if (window != null)
                    {
                        var visual = window.Content as Visual;

                        if (visual != null)
                            _adornerLayer = AdornerLayer.GetAdornerLayer(visual);
                    }
                }
                return _adornerLayer;
            }
        }

        protected UIElement AssociatedObjectParent
        {
            get { return AssociatedObject.Parent as UIElement; }
        }

        #endregion

        #region Connection Handling

        protected void StartConnection(Connection connection)
        {
            // Get all ZComponent elements at connection start point but ignore ShapeToShapeConnectionView elements.
            var startElements = ZHitTestHelper.GetElementsAtPoint<ZComponent>(AssociatedObjectParent, connection.StartPoint).Where(element => !(element is ShapeToShapeConnectionView)).ToArray();
            if (!startElements.Any())
                return;

            try
            {
                connection.Source = startElements.Single();
            }
            catch (Exception e)
            {
                Logger.ErrorException("Could not clearly distinguish source. Using first element as fallback.", e);
                connection.Source = startElements.First();
            }

            AdornerLayer.Add(new ConnectionView(AssociatedObjectParent, connection));
            ParentBehavior.RaiseConnectionStartedEvent(connection);
        }

        protected void ChangeConnection(Connection connection)
        {
            if (connection.Source == null)
                return;

            ParentBehavior.RaiseConnectionChangedEvent(connection);
        }

        protected void FinishConnection(Connection connection)
        {
            if (connection.Source == null)
                return;

            var connectionView = AdornerLayer.GetAdorners(AssociatedObjectParent).OfType<ConnectionView>().Where(view => view.Connection == connection).Single();
            AdornerLayer.Remove(connectionView);

            // Get all ZComponent elements at connection end point but ignore ShapeToShapeConnectionView elements.
            var endElements = ZHitTestHelper.GetElementsAtPoint<ZComponent>(AssociatedObjectParent, connection.EndPoint).Where(element => !(element is ShapeToShapeConnectionView)).ToArray();

            if (!endElements.Any())
            {
                CancelConnection(connection);
                return;
            }

            try
            {
                connection.Target = endElements.Single();
            }
            catch (Exception e)
            {
                Logger.ErrorException("Could not clearly distinguish target. Using first element as fallback.", e);
                connection.Target = endElements.First();
            }

            ParentBehavior.RaiseCreatConnectionFinishedEvent(connection);
        }

        protected void CancelConnection(Connection connection)
        {
            ParentBehavior.RaiseConnectionCancelledEvent(connection);
        }

        #endregion
    }
}
